﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using CommonLibrary;
using CommonLibrary.Helpers;
using CommonLibrary.Models.ControllerStates.PS3;
using ConnectionManager.ConnectionProcesors;
using ConnectionManager.Helpers;
using ConnectionManager.Models;

namespace ConnectionManager.SerialConnection.PS3
{
#pragma warning disable 612,618
    public class PS3SerialConnectionManager : IConnectionManager
    {
        private readonly SerialPort _comPort;
        private readonly IAppContext _context;
        private static IConnectionProcesor _procesor;

        private static MicroTimer _microTimer;

        public PS3SerialConnectionManager(IAppContext context)
        {
            _comPort = new SerialPort();
            _context = context;
            _comPort.DataReceived += comPort_DataRecieved;
        }

        private void comPort_DataRecieved(object sender, SerialDataReceivedEventArgs e)
        {
            LogSystem.LogErrorMessage("PS3 has send a message");
        }

        public bool Connect()
        {
            try
            {
                SerialConnectionHelper.OpenComPort(_comPort, _context.GlobalConfig.SerialPortConfig);
            }
            catch (Exception ex)
            {
                return false;
            }

            return true;
        }

        public bool Disconnect()
        {
            try
            {
                StopDataSend();
                Thread.Sleep(1);
                SerialConnectionHelper.CloseComPort(_comPort);
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        #region Send Data
        public void SendData()
        {
            // Check the game and pick a filter
            _procesor = ConnectionProcesorFactory.GetProcesor(ProcesorType.PS3Procesor, _context.ProcessedProfile.ProfileName);
            _context.GeneralInfo.PreProcesor = _procesor.GetName();

            // Start timer
            _microTimer = new MicroTimer();
            _microTimer.MicroTimerElapsed += SendDataThread;
            _microTimer.Interval = _context.GlobalConfig.SerialPortConfig.PoolRate * 1000; // x * 1000 = t ms
            _microTimer.IgnoreEventIfLateBy = 1000; // if the thread is late by 1ms skip a packet send alowing it to catch up
            _microTimer.Start();
        }

        private void SendDataThread(object sender, MicroTimerEventArgs timereventargs)
        {
            if(!_context.GeneralInfo.IsConfigurationModeActive)
                _procesor.Process(_context.ControllerState);

            var report = SixaxisPacketBuilder.CreateReportData(_context.ControllerState as PS3ControllerState);
            SerialConnectionHelper.SendData(_comPort, report); // Send the data

            /*var timelog = string.Format("Count = {0:#,0}  Timer = {1:#,0} µs," +
               " LateBy = {2:#,0} µs, ExecutionTime = {3:#,0} µs",
               timereventargs.TimerCount, timereventargs.ElapsedMicroseconds,
               timereventargs.TimerLateBy, timereventargs.CallbackFunctionExecutionTime);*/
        }

        public void StopDataSend()
        {
            if(_microTimer != null)
                _microTimer.Enabled = false;
        }
        #endregion

        public bool IsConnected()
        {
            return _comPort.IsOpen;
        }

        public List<string> GetSerialPorts()
        {
            return SerialConnectionHelper.GetComPortList();
        }
    }
#pragma warning restore 612,618
}
